import type {DomFormField, FillStrategy, Option, OptionsStrategy, SwitchOption} from "@/types.ts"

/**
 * el-input 输入框
 */
export class ElementInputStrategy implements FillStrategy {
  canHandle(el: HTMLElement) {
    return this.queryHTMLInputElement(el).classList.contains("el-input__inner")
  }

  fill(el: HTMLElement, value: any) {
    let inputEl = el.querySelector(".el-form-item__content .el-input__inner") as HTMLInputElement;
    inputEl.value = value;
    inputEl.dispatchEvent(new Event('input', {bubbles: true}));
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let inputEl = this.queryHTMLInputElement(el);
    return {
      id: inputEl.id,
      component: "",
      name: inputEl.getAttribute("name"),
      type: "input",
      label: labelEl.textContent,
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement {
    return el.querySelector(".el-form-item__content .el-input__inner") as HTMLInputElement;
  }
}

/**
 * el-select
 */
export class ElementSelectStrategy implements OptionsStrategy {
  canHandle(el: HTMLElement): boolean {
    return this.queryHTMLInputElement(el).classList.contains('el-select__input');
  }

  fill(el: HTMLElement, value: any): void {
    let options = this.parseOptions(el) as Option[];
    for (let option of options) {
      if (option.label === value) {
        document.querySelector(`#${option.id}`)?.dispatchEvent(new Event('click', {bubbles: true}));
      }
    }
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let inputElement = this.queryHTMLInputElement(el);
    let options = this.parseOptions(el) as Option[];
    return {
      component: "",
      id: inputElement.id,
      name: inputElement.name,
      type: "select",
      label: labelEl.textContent,
      options: options
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement {
    return el.querySelector(".el-select__input") as HTMLInputElement;
  }

  parseOptions(el: HTMLElement): Option[] | Option | SwitchOption {
    let inputElement = this.queryHTMLInputElement(el);
    let controlsId = inputElement.getAttribute("aria-controls");
    let optionsLiList = document.querySelectorAll(`#${controlsId} > li`);
    let options: Option[] = []
    for (let optionsLiListElement of optionsLiList) {
      options.push({
        label: optionsLiListElement.querySelector("span")?.textContent as string,
        id: optionsLiListElement.id,
      })
    }
    return options;
  }


}

/**
 * el-switch
 */
export class ElementSwitchStrategy implements OptionsStrategy {
  canHandle(el: HTMLElement): boolean {
    return this.queryHTMLInputElement(el).classList.contains('el-switch__input');
  }

  fill(el: HTMLElement, value: any): void {
    let htmlInputElement = this.queryHTMLInputElement(el);
    let trueValue = el.getAttribute("true-value");
    let falseValue = el.getAttribute("false-value");
    if (trueValue == value || falseValue == value) {
      (htmlInputElement as HTMLInputElement).checked = value;
    }
    htmlInputElement.dispatchEvent(new Event('change', {bubbles: true}));
  }

  parseOptions(el: HTMLElement): SwitchOption {
    let trueValue = el.getAttribute("true-value");
    let falseValue = el.getAttribute("false-value");
    return {
      trueValue,
      falseValue,
    }
  }

  describe(el: HTMLElement): DomFormField {
    // query label
    let labelEl = this.queryFormItemLabel(el);
    // query options
    let inputEl = this.queryHTMLInputElement(el);
    let switchOptions = this.parseOptions(inputEl)
    return {
      id: inputEl.id,
      component: "",
      type: "switch",
      label: labelEl?.textContent,
      name: "",
      switchOption: switchOptions
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement {
    return el.querySelector(".el-switch__input") as HTMLInputElement;
  }
}


/**
 * el-date-picker
 */
export class ElementDatePickerStrategy implements FillStrategy {
  canHandle(el: HTMLElement): boolean {
    return this.queryHTMLInputElement(el).classList.contains('el-date-editor__editor');
  }

  fill(el: HTMLElement, value: any): void {
    let inputEl = this.queryHTMLInputElement(el);
    inputEl.value = value;
    inputEl.dispatchEvent(new Event('input', {bubbles: true}));
    // 再模拟回车键，触发键盘事件让组件确认输入
    const enterEvent = new KeyboardEvent('keydown', {
      bubbles: true,
      cancelable: true,
      key: 'Enter',
      code: 'Enter',
    });
    inputEl.dispatchEvent(enterEvent);
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let inputEl = this.queryHTMLInputElement(el);
    return {
      id: inputEl.id,
      component: "",
      name: inputEl.getAttribute("name"),
      type: "date",
      label: labelEl.textContent,
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap > .el-form-item__label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement {
    return el.querySelector(".el-date-editor--date input.el-input__inner") as HTMLInputElement;
  }
}


/**
 * el-time-picker
 */
export class ElementTimePickerStrategy implements FillStrategy {
  canHandle(el: HTMLElement): boolean {
    return this.queryHTMLInputElement(el).classList.contains('el-time-editor__editor');
  }

  fill(el: HTMLElement, value: any): void {
    let inputEl = this.queryHTMLInputElement(el);
    inputEl.value = value;
    inputEl.dispatchEvent(new Event('input', {bubbles: true}));
    // 再模拟回车键，触发键盘事件让组件确认输入
    const enterEvent = new KeyboardEvent('keydown', {
      bubbles: true,
      cancelable: true,
      key: 'Enter',
      code: 'Enter',
    });
    inputEl.dispatchEvent(enterEvent);
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let inputEl = this.queryHTMLInputElement(el);
    return {
      id: inputEl.id,
      component: "",
      name: inputEl.getAttribute("name"),
      type: "time",
      label: labelEl.textContent,
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap > .el-form-item__label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement {
    return el.querySelector(".el-date-editor--time input.el-input__inner") as HTMLInputElement;
  }
}


/**
 * el-radio-group
 */
export class ElementRadioGroupStrategy implements OptionsStrategy {
  canHandle(el: HTMLElement): boolean {
    return el.classList.contains('el-radio-group');
  }

  fill(el: HTMLElement, value: any): void {
    let inputElementNodeListOf = this.queryHTMLInputElement(el);
    for (let inputElement of inputElementNodeListOf) {
      if (inputElement.value === value) {
        (inputElement as HTMLInputElement).checked = true;
        inputElement.dispatchEvent(new Event('change', {bubbles: true}));
      }
    }
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let radioGroupElement = el.querySelector('.el-radio-group') as HTMLElement;
    return {
      id: radioGroupElement.id,
      type: "radio",
      label: labelEl.textContent,
      options: this.parseOptions(el)
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap .el-form-item__label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): NodeListOf<HTMLInputElement> {
    return el.querySelectorAll(".el-radio__input .el-radio__original")
  }

  parseOptions(el: HTMLElement): Option[] {
    let options: Option[] = [];
    let radioElList = el.querySelectorAll('.el-radio-group .el-radio');
    for (let radioElement of radioElList) {
      let radioLabel = radioElement.querySelector(".el-radio__label") as HTMLElement;
      let radioInputElement = radioElement.querySelector(".el-radio__input .el-radio__original") as HTMLInputElement;
      options.push({
        label: radioLabel.textContent ?? "",
        id: radioInputElement.id,
        value: radioInputElement ? (radioInputElement as HTMLInputElement).value : "",
        name: radioInputElement.name
      })

    }
    return options;
  }
}


/**
 * el-checkbox-group
 */
export class ElementCheckboxGroupStrategy implements OptionsStrategy {
  canHandle(el: HTMLElement): boolean {
    return el.classList.contains('el-checkbox-group');
  }

  fill(el: HTMLElement, value: any[]): void {
    let inputElementNodeListOf = this.queryHTMLInputElement(el);
    for (let inputElement of inputElementNodeListOf) {
      if (value.includes(inputElement.value)) {
        console.log("zz", inputElement);
        // 代码几乎是同步连续执行的：
        // 第一次点击触发更新（异步，Vue 下一轮更新才生效）
        // 第二次点击立刻执行，覆盖了前一次未完成的变更
        // ⚠️ 最终 v-model 只记录最后一次点击结果！
        // 解决方法：使用 setTimeout 延迟执行，确保前一次变更完成
        setTimeout(() => {
          (inputElement as HTMLInputElement).checked = true;
          inputElement.dispatchEvent(new Event('change', {bubbles: true}));
        }, 0)
      }
    }
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let checkboxGroupElement = el.querySelector('.el-checkbox-group') as HTMLElement;
    return {
      id: checkboxGroupElement.id,
      type: "checkbox-group",
      label: labelEl.textContent,
      options: this.parseOptions(el)
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap .el-form-item__label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): NodeListOf<HTMLInputElement> {
    return el.querySelectorAll(".el-checkbox__input .el-checkbox__original");
  }

  parseOptions(el: HTMLElement): Option[] {
    let options: Option[] = [];
    let checkboxElList = el.querySelectorAll('.el-checkbox-group .el-checkbox');
    for (let checkboxElement of checkboxElList) {
      let checkboxLabel = checkboxElement.querySelector(".el-checkbox__label") as HTMLElement;
      let checkboxInputElement = checkboxElement.querySelector(".el-checkbox__input .el-checkbox__original") as HTMLInputElement;
      options.push({
        label: checkboxLabel.textContent ?? "",
        id: checkboxInputElement.id,
        value: checkboxInputElement ? (checkboxInputElement as HTMLInputElement).value : "",
        name: checkboxInputElement.name
      })
    }
    return options;
  }
}


/**
 * textarea
 */
export class ElementTextareaStrategy implements FillStrategy {
  canHandle(el: HTMLElement): boolean {
    return this.queryHTMLInputElement(el).classList.contains('el-textarea__inner');
  }

  fill(el: HTMLElement, value: any): void {
    let inputEl = this.queryHTMLInputElement(el);
    inputEl.value = value;
    inputEl.dispatchEvent(new Event('input', {bubbles: true}));
  }

  describe(el: HTMLElement): DomFormField {
    let labelEl = this.queryFormItemLabel(el);
    let inputEl = this.queryHTMLInputElement(el);
    return {
      id: inputEl.id,
      component: "",
      name: inputEl.getAttribute("name"),
      type: "textarea",
      label: labelEl.textContent,
    };
  }

  queryFormItemLabel(el: HTMLElement): HTMLElement {
    return el.querySelector(".el-form-item__label-wrap label") as HTMLElement;
  }

  queryHTMLInputElement(el: HTMLElement): HTMLInputElement  {
    return el.querySelector(".el-textarea__inner") as HTMLInputElement;
  }
}
